package net.luohuasheng.bee.proxy.mybatis.executor.processor;

import net.luohuasheng.bee.proxy.core.utils.StringUtils;
import net.luohuasheng.bee.proxy.core.utils.convert.ValueConvertUtils;
import net.luohuasheng.bee.proxy.core.utils.jpa.JpaModelUtils;
import net.luohuasheng.bee.proxy.core.utils.jpa.annotation.TableLogic;
import net.luohuasheng.bee.proxy.core.utils.jpa.dto.JpaColumnDto;
import net.luohuasheng.bee.proxy.core.utils.jpa.dto.JpaTableDto;
import net.luohuasheng.bee.proxy.mybatis.common.exception.MybatisException;
import net.luohuasheng.bee.proxy.mybatis.common.utils.CrudUtils;
import net.luohuasheng.bee.proxy.mybatis.common.utils.MapperUtils;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.session.Configuration;

import java.util.ArrayList;
import java.util.List;

import static net.luohuasheng.bee.proxy.mybatis.executor.intercetor.BaseInterceptor.Index.MAPPED_STATEMENT_INDEX;
import static net.luohuasheng.bee.proxy.mybatis.executor.intercetor.BaseInterceptor.LANGUAGE_DRIVER;

public class InsertSelectiveProcessor extends BaseProcessor {
    public static final String INSERT_SELECTIVE = "INSERT SELECTIVE";


    public InsertSelectiveProcessor(Configuration configuration, Class<?> entityClass) {
        super(configuration, entityClass);
    }

    @Override
    public void rewrite(Invocation invocation, MappedStatement ms, BoundSql boundSql, Object parameter) throws Exception {
        String sql = boundSql.getSql();
        Class<?> emptyClass = null;
        if (parameter == null) {
            throw new MybatisException("empty value");
        } else {
            String className = sql.replace(INSERT_SELECTIVE, "").trim();
            emptyClass = CrudUtils.class.getClassLoader().loadClass(className);
        }
        JpaTableDto jpaTableDto = JpaModelUtils.getJpaTable(emptyClass);
        List<JpaColumnDto> fields = new ArrayList<>();

        for (JpaColumnDto column : jpaTableDto.getColumns()) {
            column.getField().setAccessible(true);
            if (column.getTableLogic() != null) {
                TableLogic logic = column.getTableLogic();
                column.getField().set(parameter, ValueConvertUtils.convert(logic.noDelFlag(), column.getField().getType()));
            }
            Object value = column.getField().get(parameter);
            column.getField().setAccessible(false);
            if (column.isPk()) {
                fields.add(column);
            } else if (value instanceof String) {
                if (StringUtils.isNotEmpty(value.toString())) {
                    fields.add(column);
                }
            } else if (value != null) {
                fields.add(column);
            }
        }
        String[] fieldNames = new String[fields.size()];
        String[] columnNames = new String[fields.size()];
        for (int i = 0; i < fields.size(); i++) {
            JpaColumnDto column = fields.get(i);
            fieldNames[i] = "#{" + column.getField().getName() + "}";
            columnNames[i] = column.getName();
        }
        SQL insertInto = new SQL().INSERT_INTO(jpaTableDto.getName());
        insertInto.INTO_COLUMNS(columnNames);
        insertInto.INTO_VALUES(fieldNames);
        sql = insertInto.toString();
        SqlSource sqlSource = LANGUAGE_DRIVER.createSqlSource(ms.getConfiguration(), "<script>\n\t" + sql + "</script>", null);
        BoundSql newBoundSql = sqlSource.getBoundSql(parameter);
        invocation.getArgs()[MAPPED_STATEMENT_INDEX.getAnInt()] = MapperUtils.copyFromNewSql(ms, newBoundSql);
    }


    @Override
    public SqlSource createSqlSource() {
        return createSqlSource(INSERT_SELECTIVE + " " + entityClass.getName());
    }


    @Override
    public KeyGenerator keyGenerator() {
        return getKey().getKeyGenerator();
    }

    @Override
    public String keyProperty() {
        return getKey().getKeyProperty();
    }

    @Override
    public String keyColumn() {
        return getKey().getKeyProperty();
    }


}
